package com.wzdigit.wms.wms.service.transfer;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.wzdigit.framework.Shift;
import com.wzdigit.mes.basic.api.BasicSimpleCodeRuleApi;
import com.wzdigit.wms.basic.client.Pager;
import com.wzdigit.wms.basic.client.PagerInfo;
import com.wzdigit.wms.basic.client.request.transfer.*;
import com.wzdigit.wms.basic.client.response.Result;
import com.wzdigit.wms.basic.client.response.transfer.*;
import com.wzdigit.wms.basic.domain.dtos.transfer.GdnUnPickGroupWhsDto;
import com.wzdigit.wms.basic.domain.inventory.Lotno;
import com.wzdigit.wms.basic.domain.transfer.*;
import com.wzdigit.wms.basic.enums.*;
import com.wzdigit.wms.basic.mapper.core.transfer.*;
import com.wzdigit.wms.basic.util.DateUtils;
import com.wzdigit.wms.basic.util.HttpSessionUtil;
import com.wzdigit.wms.basic.util.StringUtils;
import com.wzdigit.wms.basic.util.WrapperUtil;
import com.wzdigit.wms.basic.util.common.FileUrlString;
import com.wzdigit.wms.basic.util.common.LockNumber;
import com.wzdigit.wms.basic.util.common.LockString;
import com.wzdigit.wms.common.entity.StatusCode;
import com.wzdigit.wms.wms.constant.FilePathConstant;
import com.wzdigit.wms.wms.service.basic.FileService;
import com.wzdigit.wms.wms.service.basic.WarehouseService;
import com.wzdigit.wms.basic.service.code.LotnoService;
import com.wzdigit.wms.basic.service.code.RedisService;
import lombok.extern.slf4j.Slf4j;
import net.dreamlu.mica.core.utils.BeanUtil;
import net.sf.jasperreports.engine.DefaultJasperReportsContext;
import net.sf.jasperreports.engine.JRPropertiesUtil;
import net.sf.jasperreports.engine.JasperExportManager;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.JasperReport;
import net.sf.jasperreports.engine.export.ooxml.JRXlsxExporter;
import net.sf.jasperreports.engine.util.JRLoader;
import net.sf.jasperreports.export.ExporterInput;
import net.sf.jasperreports.export.OutputStreamExporterOutput;
import net.sf.jasperreports.export.SimpleExporterInput;
import net.sf.jasperreports.export.SimpleOutputStreamExporterOutput;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.sql.DataSource;
import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.sql.Connection;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 发货单-服务类
 * @author yangdongjie
 * @GdnService.java
 * @2021年2月24日下午3:25:03
 */
@Service
@Slf4j
public class GdnService {

	@Autowired
	FileService fileService;

	@Autowired
	private GdnRemainHeaderMapper gdnRemainHeaderMapper;
	
	@Autowired
	private PicktaskDtlMapper picktaskDtlMapper;
	
	@Autowired
	private GdnDtlGoodsMapper gdnDtlGoodsMapper;
	
	@Autowired
	private CtnrLoadingMapper ctnrLoadingMapper;
	
	@Autowired
    private DocPreAlocMapper docPreAlocMapper;
	
	@Autowired
	private GdnHeaderMapper gdnHeaderMapper;
	
	@Autowired
	private InvZoneMapper invZoneMapper;
	
	@Autowired
	private GdnDtlMapper gdnDtlMapper;
	
	@Autowired
    private LotnoService lotnoService;
	
	@Autowired
	private WarehouseService warehouseService;
	
	@Autowired
	private DataSource dataSource;
	
	@Autowired
    private RedisService redisService;
	
	@Reference(version = "${dubbo.consumers.basic.simple.code.rule.api:1.0.0}", check = false)
    private BasicSimpleCodeRuleApi basicSimpleCodeRuleApi;
	
	/**
	 * 发货单列表
	 * @param dto
	 * @return
	 * 【是否允许打印预留单】余留数量 > 0 
	 * 【是否允许打印发货单】只要有一笔明细仓库不为空
	 */
	public PagerInfo<List<GdnHeaderListResponse>> searchGdnHeader(SearchGdnHeaderRequest dto, Pager<?> pager) {
    	Page<?> page = PageHelper.offsetPage(pager.getSkipCount(), pager.getMaxResultCount());
        PagerInfo<List<GdnHeaderListResponse>> pagerInfo = new PagerInfo<List<GdnHeaderListResponse>>();
        
        // 发货时间
        Date beginShipDate = null, endShipDate = null;
        if(dto.getShipTime() != null) {
        	beginShipDate = DateUtils.getStartTime(dto.getShipTime());
        	endShipDate = DateUtils.getEndTime(dto.getShipTime());
        }
        
        // 截关时间
        Date beginClosingDate = null, endClosingDate = null;
        if(dto.getClosingTime() != null) {
        	beginClosingDate = DateUtils.getStartTime(dto.getClosingTime());
        	endClosingDate = DateUtils.getEndTime(dto.getClosingTime());
        }
        
        // 发货单明细状态
        List<Integer> gdnDtlStatusList = new ArrayList<>();
        if(dto.getIsWaitPick() != null && dto.getIsWaitPick()) {	// 待拣货
        	gdnDtlStatusList.add(GdnDtlStatusEnum.WAITPICK.code);
        }
        if(dto.getIsNotFinish() != null && dto.getIsNotFinish()) {	// 未完成
        	gdnDtlStatusList.add(GdnDtlStatusEnum.CREATE.code);
        	gdnDtlStatusList.add(GdnDtlStatusEnum.HASDONE.code);
        	gdnDtlStatusList.add(GdnDtlStatusEnum.WAITPICK.code);
        	gdnDtlStatusList.add(GdnDtlStatusEnum.PICKING.code);
        	gdnDtlStatusList.add(GdnDtlStatusEnum.WAITLOAD.code);
        	gdnDtlStatusList.add(GdnDtlStatusEnum.LOADING.code);
        	gdnDtlStatusList.add(GdnDtlStatusEnum.SHIPMENTING.code);
        }
        
        List<GdnHeaderListResponse> list = new ArrayList<>(0);
        if(dto.getGdnType() == null || GdnTypeEnum.D01.code.equals(dto.getGdnType())){
        	dto.setGdnType(GdnTypeEnum.D01.code);
        	list = gdnHeaderMapper.selectAll(dto, gdnDtlStatusList, beginShipDate, endShipDate, beginClosingDate, endClosingDate);
        }
        pagerInfo.setTotalCount(page.getTotal());
        pagerInfo.setItems(list);
		return pagerInfo;
    }
	
	/**
	 * 发货单明细列表
	 * @param dto
	 * @return
	 * 【是否允许分配库存】	UDF1 = NO
	 * 【是否允许取消分配库存】	(UDF1 = YES & 拣货任务标识 = 0（未生成）) || (UDF1 = NO & WHS_ID != NULL)
	 * 【是否允许排柜】		UDF1 = YES & 发货单明细排柜状态 = 0(未排柜) & 发货单明细状态 != (0：取消、6：装柜中、7：已发运、8：关闭)
	 */
	public PagerInfo<List<GdnDtlListResponse>> searchGdnDtl(SearchGdnDtlRequest dto, Pager<?> pager) {
    	Page<?> page = PageHelper.offsetPage(pager.getSkipCount(), pager.getMaxResultCount());
        PagerInfo<List<GdnDtlListResponse>> pagerInfo = new PagerInfo<List<GdnDtlListResponse>>();
        
        // 发货单明细状态
        List<Integer> gdnDtlStatusList = new ArrayList<>();
        if(dto.getIsWaitPick() != null && dto.getIsWaitPick()) {	// 待拣货
        	gdnDtlStatusList.add(GdnDtlStatusEnum.WAITPICK.code);
        }
        if(dto.getIsNotFinish() != null && dto.getIsNotFinish()) {	// 未完成
        	gdnDtlStatusList.add(GdnDtlStatusEnum.CREATE.code);
        	gdnDtlStatusList.add(GdnDtlStatusEnum.HASDONE.code);
        	gdnDtlStatusList.add(GdnDtlStatusEnum.WAITPICK.code);
        	gdnDtlStatusList.add(GdnDtlStatusEnum.PICKING.code);
        	gdnDtlStatusList.add(GdnDtlStatusEnum.WAITLOAD.code);
        	gdnDtlStatusList.add(GdnDtlStatusEnum.LOADING.code);
        	gdnDtlStatusList.add(GdnDtlStatusEnum.SHIPMENTING.code);
        	gdnDtlStatusList.add(GdnDtlStatusEnum.SHIPMENTED.code);
        }
        
        List<GdnDtlListResponse> list = gdnDtlMapper.selectAll(dto.getGdnHeaderId(), gdnDtlStatusList);
        for (GdnDtlListResponse one : list) {
			if(one.getAllowAloc()) {
				one.setIsCreatePicktaskText("否（未预配）");
			} else if (!Objects.equals(PicktaskFlagEnum.UN_CREATED.code, one.getPickTaskFlag())) {
				one.setIsCreatePicktaskText("否（已生成）");
			} else {
				one.setIsCreatePicktaskText("是");
			}
		}
        pagerInfo.setItems(list);
        pagerInfo.setTotalCount(page.getTotal());
		return pagerInfo;
    }
	
	/**
	 * 拣货进度详情
	 * @param pager
	 * @return
	 */
	public <T> PagerInfo<List<PickTaskProgressResponse>> searchPickTaskProgress(Integer gdnHeaderId, Pager<T> pager) {
    	Page<?> page = PageHelper.offsetPage(pager.getSkipCount(), pager.getMaxResultCount());
        PagerInfo<List<PickTaskProgressResponse>> pagerInfo = new PagerInfo<List<PickTaskProgressResponse>>();
        List<PickTaskProgressResponse> list = picktaskDtlMapper.selectPickTaskProgress(gdnHeaderId);
        pagerInfo.setItems(list);
        pagerInfo.setTotalCount(page.getTotal());
		return pagerInfo;
    }
	
	/**
	 * 发货单明细货品清单列表
	 * @param gdnDtlId
	 * @param pager
	 * @return
	 */
	public <T> PagerInfo<List<GdnDtlGoodsListResponse>> searchGdnDtlGoods(Integer gdnDtlId, Pager<T> pager) {
    	Page<?> page = PageHelper.offsetPage(pager.getSkipCount(), pager.getMaxResultCount());
        PagerInfo<List<GdnDtlGoodsListResponse>> pagerInfo = new PagerInfo<List<GdnDtlGoodsListResponse>>();
        List<GdnDtlGoodsListResponse> list = gdnDtlGoodsMapper.selectAll(gdnDtlId);
        pagerInfo.setItems(list);
        pagerInfo.setTotalCount(page.getTotal());
		return pagerInfo;
    }
	
	/**
	 * 发货单排柜信息列表
	 * @param gdnHeaderId
	 * @param pager
	 * @return
	 * 【是否允许增加货柜】（发货）装柜数量 >0 & 计划装柜数量 > （发货）装柜数量  & 未完成（!=3）
	 */
	public <T> PagerInfo<List<CtnrLoadingResponse>> searchCtnrLoading(Integer gdnHeaderId, Pager<T> pager) {
    	Page<?> page = PageHelper.offsetPage(pager.getSkipCount(), pager.getMaxResultCount());
        PagerInfo<List<CtnrLoadingResponse>> pagerInfo = new PagerInfo<List<CtnrLoadingResponse>>();
        List<CtnrLoadingResponse> list = ctnrLoadingMapper.selectByGdnHeaderId(gdnHeaderId);
        pagerInfo.setItems(list);
        pagerInfo.setTotalCount(page.getTotal());
		return pagerInfo;
    }
	
	/**
	 * 编辑货柜
	 * 
	 * @param dto
	 * @param servletRequest
	 * @return
	 */
	@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
	public Result<?> updateCtnrLoading(UpdateCtnrLoadingRequest dto, HttpServletRequest servletRequest) {
		String loginName = HttpSessionUtil.getLoginName(servletRequest);
		
		CtnrLoading ctnrLoading = ctnrLoadingMapper.selectById(dto.getCtnrLoadingId());
    	BeanUtil.copy(dto, ctnrLoading);
    	ctnrLoading.setModifyUser(loginName);
    	ctnrLoading.setModifyTime(new Date());
    	ctnrLoadingMapper.updateById(ctnrLoading);
    	
		return new Result<>();
	}
	
	
	/**
	 * 获取可用库存
	 * @param gdnDtlId
	 * @return
	 * 
	 * 【是否允许分配库存】UDF1 = NO
	 * [1]来源：库区库存表（WMS_INV_ZOON），参考可用库存=库存数-预支-分配数-冻结数-按发货单统计的未拣货数量
	 *	     取数条件：已分库、状态≠取消、完成或关闭，未拣货数量=计划数量-已拣货数量
	 *	     取消库区预占逻辑(不增加库区库存表预分配数量)
	 * [2]取数条件：
	 *	货主+货品+工厂代码(组织)+供应商+批次号+库存性质+品质状态
	 *	其中发货单明细中的批次号若为空，且启用了批次属性管理，则需通过批次属性转换为批次号。
	 *	[3]本次分配:可修改，不大于可用库存数，本次分配合计=已分配数，需小于需求数量
	 */
	public List<AvailableInvZoneGroupWhsResponse> getAvailableInvZone(Long gdnDtlId,
			HttpServletRequest servletRequest) {
		GdnDtl gdnDtl = gdnDtlMapper.selectById(gdnDtlId);
		if (GdnDtlUdf1Enum.YES.code.equals(gdnDtl.getUdf1())) {
			Shift.fatal(StatusCode.NOTCAN_PREALOC);
		}
		
		// 找批次号
		String lotnoStr = gdnDtl.getLotno();
		if(StringUtils.isNull(lotnoStr)) {
			Lotno lotno = lotnoService.getLotnoByGdnDtlId(gdnDtlId);
			if(lotno == null) {
				// 无法匹配到批次号
				Shift.fatal(StatusCode.LOTNO_NULL);
			}
			lotnoStr = lotno.getLotno();
		}
		
		// 查询当前用户权限仓库
		List<Integer> whsIdList = warehouseService.getWareHouseIds(servletRequest);
		// 发货单表头
		GdnHeader gdnHeader = gdnHeaderMapper.selectById(gdnDtl.getGdnHeaderId());
		
        SearchInvRequest dto = new SearchInvRequest();
        dto.setLotno(lotnoStr);
        dto.setSkuId(gdnDtl.getSkuId());
        dto.setVendorId(gdnDtl.getVendor());
        dto.setInvAttr(gdnDtl.getInvAttr());
        dto.setQaStatus(gdnDtl.getQaStatus());
        dto.setFactory(gdnHeader.getFactory());
        List<AvailableInvZoneGroupWhsResponse> availableInvZoneGroupWhs = invZoneMapper.getAvailableInvZoneGroupWhs(dto, whsIdList, WarehouseEnum.availableInvWhsTypeList);
        if(availableInvZoneGroupWhs.size() > 0) {
        	List<Integer> gdnWhsIdList = availableInvZoneGroupWhs.stream().map(AvailableInvZoneGroupWhsResponse::getWhsId).distinct().collect(Collectors.toList());
        	List<GdnUnPickGroupWhsDto> unPickGroupWhsList = gdnDtlMapper.selectUnPickGroupWhs(gdnDtl.getSkuId(), lotnoStr, gdnWhsIdList);
        	Map<Integer, GdnUnPickGroupWhsDto> unPickGroupWhsMap = unPickGroupWhsList.stream().collect(Collectors.toMap(GdnUnPickGroupWhsDto::getWhsId, gdnUnPickGroupWhsDto -> gdnUnPickGroupWhsDto));
    		for (AvailableInvZoneGroupWhsResponse one : availableInvZoneGroupWhs) {
    			GdnUnPickGroupWhsDto gdnUnPickGroupWhsDto = unPickGroupWhsMap.get(one.getWhsId());
    			if(gdnUnPickGroupWhsDto != null) {
    				BigDecimal unPickQty = gdnUnPickGroupWhsDto.getOrderQty().subtract(gdnUnPickGroupWhsDto.getPickQty());
    				one.setAvailableQty(one.getAvailableQty().subtract(unPickQty));
    			}
			}
        }
        // 过滤掉可用库存小于等于0的
        availableInvZoneGroupWhs = availableInvZoneGroupWhs.stream().filter(a -> a.getAvailableQty().signum() == 1).collect(Collectors.toList());
        availableInvZoneGroupWhs = availableInvZoneGroupWhs.stream().sorted(Comparator.comparing(AvailableInvZoneGroupWhsResponse::getAvailableQty).reversed()).collect(Collectors.toList());
		return availableInvZoneGroupWhs;
    }
	
	/**
	 * 排柜
	 * @param dto
	 * @param servletRequest
	 * @return
	 * 
	 * a.校验：
	 * 	UDF1 = YES & 发货单明细排柜状态 = 0(未排柜) & 发货单明细状态 != (0：取消、6：装柜中、7：已发运、8：关闭)
	 *  [1]柜型：柜型由发货单表头表(参考柜型)带出，不可修改；
	 *	[2]【确定】按钮：调用【发货单实际排柜】服务，为选中的发货单明细的实际排柜信息
	 *	写入到装柜表(WMS_CTNR_LOADING)，同时切换到【排柜信息】tab页
	 */
	@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
	public synchronized Result<?> rowCtnrLoading(RowCtnrLoadingRequest dto, HttpServletRequest servletRequest) {
		String loginName = HttpSessionUtil.getLoginName(servletRequest);
		Date date = new Date();
		
		// 发货单表头
		QueryWrapper<GdnHeader> gdnHeaderQueryWrapper = new QueryWrapper<GdnHeader>();
		gdnHeaderQueryWrapper.eq("GDN_NO", dto.getGdnNo());
		GdnHeader gdnHeader = gdnHeaderMapper.selectOne(gdnHeaderQueryWrapper);
		
		// 发货单明细
		QueryWrapper<GdnDtl> gdnDtlQueryWrapper = new QueryWrapper<GdnDtl>();
		gdnDtlQueryWrapper.in("GDN_DTL_ID", dto.getGdnDtlIds());
		for (GdnDtl gdnDtl : gdnDtlMapper.selectList(gdnDtlQueryWrapper)) {
			//校验：发货单明细状态=0(取消)/6(装柜中)/7(已发运)/8(关闭)，或者发货单明细预配数=0
			if (GdnDtlUdf1Enum.NO.code.equals(gdnDtl.getUdf1())
					|| GdnDtlStatusEnum.CLOSE.code == gdnDtl.getStatus()
					|| GdnDtlStatusEnum.CANCEL.code == gdnDtl.getStatus()
					|| GdnDtlStatusEnum.LOADING.code == gdnDtl.getStatus()
					|| GdnDtlStatusEnum.SHIPMENTED.code == gdnDtl.getStatus()
					|| GdnDtlArrangeCtnrFlagEnum.YES.code == gdnDtl.getArrangeCtnrFlag()) {
				Shift.fatal(StatusCode.NOTCAN_ROWCTNRLOADING);
			} else {
				// 更新发货单明细
				gdnDtl.setModifyTime(date);
				gdnDtl.setModifyUser(loginName);
				gdnDtl.setArrangeCtnrFlag(GdnDtlArrangeCtnrFlagEnum.YES.code);
				gdnDtlMapper.updateById(gdnDtl);
				
				// 新增排柜单信息
				CtnrLoading ctnrLoading = new CtnrLoading();
		    	ctnrLoading.setGdnNo(dto.getGdnNo());
		    	ctnrLoading.setCntrNo(dto.getCntrNo());
		    	ctnrLoading.setSealNo(dto.getSealNo());
		    	ctnrLoading.setCntrType(dto.getCntrType());
		    	ctnrLoading.setBookingNo(dto.getBookingNo());
		    	ctnrLoading.setVehicleNo(dto.getVehicleNo());
		    	
		    	ctnrLoading.setCreateTime(date);
		    	ctnrLoading.setCreateUser(loginName);
		    	ctnrLoading.setCmpQty(BigDecimal.ZERO);
		    	ctnrLoading.setStatus(CtnrLoadingStatusEnum.CREATE.code);
		    	
		    	ctnrLoading.setPlanQty(gdnDtl.getOrderQty());
		    	ctnrLoading.setGdnDtlId(gdnDtl.getGdnDtlId());
		    	ctnrLoading.setGdnLineNo(gdnDtl.getGdnLineNo());
		    	
		    	ctnrLoading.setCntrSeq(gdnHeader.getCntrSeq());
		    	ctnrLoading.setCarrier(gdnHeader.getCarrierId());
		    	ctnrLoading.setRefCntrNo(gdnHeader.getRefCntrNo());
		    	ctnrLoading.setRefCntrType(gdnHeader.getCntrType());
		    	ctnrLoading.setDockOfLoading(gdnHeader.getShipPort());			// 装柜码头
		    	ctnrLoading.setPlanLoadingTime(gdnHeader.getPlanLoadingTime());
		    	ctnrLoadingMapper.insert(ctnrLoading);
			}
		}
		
		// 更新表头的装柜信息
		gdnHeader.setCntrNo(dto.getCntrNo());
		gdnHeader.setSealNo(dto.getSealNo());
		gdnHeader.setCntrType(dto.getCntrType());
		gdnHeader.setBookingNo(dto.getBookingNo());
		gdnHeader.setVehicleNo(dto.getVehicleNo());
		gdnHeaderMapper.updateCtnrLoading(gdnHeader);
		return new Result<>();
	}

	/**
	 * 增加货柜
	 * 
	 * @param dto
	 * @param servletRequest
	 * @return
	 * 
	 * 校验：实际已装柜数量>0 且 剩余未装柜数量>0 且 未完成（不等于3）
	 * [1].柜型：柜型通过数据字典配置
	 * [2].【确定】按钮：调用【装柜单更新】服务和【发货单增加实际货柜】服务，
	 * 更新选中的装柜单信息(减少计划装柜数量)、将新增的装柜单信息写入装柜单表(WMS_CTNR_LOADING)；
	 */
	@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
	public synchronized Result<?> addCtnrLoading(AddCtnrLoadingRequest dto, HttpServletRequest servletRequest) {
		// 【行级锁】控制到每个装柜单
		QueryWrapper<CtnrLoading> lockWrapper = WrapperUtil.lock(CtnrLoading.class);
		lockWrapper.in("CTNR_LOADING_ID", dto.getCtnrLoadingIds());
		List<CtnrLoading> ctnrLoadingList = ctnrLoadingMapper.selectList(lockWrapper);
		
		String loginName = HttpSessionUtil.getLoginName(servletRequest);
		Date date = new Date();
		
		for (CtnrLoading ctnrLoading : ctnrLoadingList) {
			// 校验：实际已装柜数量>0且剩余未装柜数量>0
			if(ctnrLoading.getPlanQty() != null && 
				ctnrLoading.getCmpQty() != null &&
				ctnrLoading.getCmpQty().intValue() > 0 && 
				ctnrLoading.getPlanQty().intValue() > ctnrLoading.getCmpQty().intValue() &&
				CtnrLoadingStatusEnum.FINISH.code != ctnrLoading.getStatus()) {
				
				// 剩下多少未装柜
				BigDecimal subtract = ctnrLoading.getPlanQty().subtract(ctnrLoading.getCmpQty());
				
				// 更新选中的装柜单信息(减少计划装柜数量)
				ctnrLoading.setModifyTime(date);
				ctnrLoading.setModifyUser(loginName);
				ctnrLoading.setPlanQty(ctnrLoading.getCmpQty());
				ctnrLoadingMapper.updateById(ctnrLoading);
				
				// 将新增的装柜单信息写入装柜单表(WMS_CTNR_LOADING)
				CtnrLoading newCtnrLoading = new CtnrLoading();
				newCtnrLoading.setGdnNo(ctnrLoading.getGdnNo());
		    	newCtnrLoading.setGdnDtlId(ctnrLoading.getGdnDtlId());
		    	newCtnrLoading.setGdnLineNo(ctnrLoading.getGdnLineNo());
		    	
				newCtnrLoading.setCntrNo(dto.getCntrNo());
				newCtnrLoading.setSealNo(dto.getSealNo());
				newCtnrLoading.setCntrType(dto.getCntrType());
				newCtnrLoading.setBookingNo(dto.getBookingNo());
				newCtnrLoading.setVehicleNo(dto.getVehicleNo());
				
		    	newCtnrLoading.setCreateTime(date);
		    	newCtnrLoading.setPlanQty(subtract);
		    	newCtnrLoading.setCreateUser(loginName);
		    	newCtnrLoading.setCmpQty(BigDecimal.ZERO);
		    	newCtnrLoading.setStatus(CtnrLoadingStatusEnum.CREATE.code);
		    	ctnrLoadingMapper.insert(newCtnrLoading);
			} else {
				Shift.fatal(StatusCode.NOTCAN_ADDCTNRLOADING);
			}
		}
		return new Result<>();
	}
	
	/**
	 * 确认分配库存
	 * @param dto
	 * @param servletRequest
	 * @return
	 * 
	 * 【是否允许分配库存】UDF1 = NO
	 * [1]检验：已分配数=需求数量，否则提示“请分配足够库存！”；
	 * [2]根据仓库的分配数量，系统将分配数量按每个库区的可用库存数拆分到库区；
	 * [3]调用【发货单库存预配】服务将数据保存到发货单预配表(WMS_GDN_PRE_ALOC)、
	 * 更新库区库存表(WMS_INV_ZONE，增加库区预配库存)
	 * @throws Exception 
	 * @throws  
	 */
	@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
	public synchronized Result<?> confirmInvZone(ConfirmInvZoneRequest dto,
			HttpServletRequest servletRequest) throws Exception {
		// 发货单明细
		GdnDtl gdnDtl = gdnDtlMapper.selectById(dto.getDtlId());
		if (GdnDtlUdf1Enum.YES.code.equals(gdnDtl.getUdf1())) {
			Shift.fatal(StatusCode.NOTCAN_PREALOC);
		}
		// 锁定发货单dtl
		String lockKeyStr = LockString.WMS_GDN_DTL_LOCK_KEY + gdnDtl.getGdnDtlId();
		if (redisService.lock(lockKeyStr, LockNumber.SECONDS_II)) {
			try {
				// 分配库存总数
				int qty = 0;
				List<ConfirmInvZoneItemRequest> items = dto.getItems();
				for (ConfirmInvZoneItemRequest item : items) {
					qty += item.getQty().intValue();
				}
				
				if(qty == 0) {
					// 分配数 = 0
					Shift.fatal("分配数量不能为0！");
				}
				
				// 需求数量
				int orderQty = gdnDtl.getOrderQty().intValue();
				if(orderQty < qty) {
					// 需求数量 < 分配数
					Shift.fatal("分配数量不能大于需求数量！");
				}
				
				// 剩下未分配的数量
				int remainQty = orderQty - qty;
				
				// 找批次号
				String lotnoStr = gdnDtl.getLotno();
				if(StringUtils.isNull(lotnoStr)) {
					Lotno lotno = lotnoService.getLotnoByGdnDtlId(gdnDtl.getGdnDtlId());
					if(lotno == null) {
						// 无法匹配到批次号
						Shift.fatal(StatusCode.LOTNO_NULL);
					}
					lotnoStr = lotno.getLotno();
				}
				
				// 查询当前用户权限仓库
				List<Integer> whsIdList = warehouseService.getWareHouseIds(servletRequest);
				
				// 发货单表头
				GdnHeader gdnHeader = gdnHeaderMapper.selectById(gdnDtl.getGdnHeaderId());
				String loginName = HttpSessionUtil.getLoginName(servletRequest);
				Date date = new Date();
				
				// 排柜单信息
				CtnrLoading ctnrLoading = null;
				if(gdnHeader.getCntrNo() != null || gdnHeader.getSealNo() != null || 
						gdnHeader.getBookingNo() != null || gdnHeader.getVehicleNo() != null) {
					ctnrLoading = new CtnrLoading();
					ctnrLoading.setGdnNo(gdnHeader.getGdnNo());
			    	ctnrLoading.setCntrNo(gdnHeader.getCntrNo());
			    	ctnrLoading.setSealNo(gdnHeader.getSealNo());
			    	ctnrLoading.setCntrType(gdnHeader.getCntrType());
			    	ctnrLoading.setBookingNo(gdnHeader.getBookingNo());
			    	ctnrLoading.setVehicleNo(gdnHeader.getVehicleNo());
			    	
			    	ctnrLoading.setCreateTime(date);
			    	ctnrLoading.setCreateUser(loginName);
			    	ctnrLoading.setCmpQty(BigDecimal.ZERO);
			    	ctnrLoading.setStatus(CtnrLoadingStatusEnum.CREATE.code);
			    	
			    	ctnrLoading.setCntrSeq(gdnHeader.getCntrSeq());
			    	ctnrLoading.setCarrier(gdnHeader.getCarrierId());
			    	ctnrLoading.setRefCntrNo(gdnHeader.getRefCntrNo());
			    	ctnrLoading.setRefCntrType(gdnHeader.getCntrType());
			    	ctnrLoading.setDockOfLoading(gdnHeader.getShipPort());			// 装柜码头
			    	ctnrLoading.setPlanLoadingTime(gdnHeader.getPlanLoadingTime());
				}
				
				// 锁住最大行号
		        Integer lockMaxGdnLineNo = 0;
		        if(items.size() > 0 || remainQty > 0) {
		        	lockMaxGdnLineNo = gdnDtlMapper.lockMaxGdnLineNo(gdnHeader.getGdnHeaderId());
		        }
		        
		        // 仓库预配数量
		        int whsPreAlocQty;
		        // 库区预配数量
				int zonePreAlocQty;
				// 仓库的可用数量
				int whsAvailableQty;
				// 库区的可用数量
				int zoneAvailableQty;
		        
		        // 遍历每个仓库分配多少数量
		        int i = 0;
		        
				// 查找库区库存入参DTO
				SearchInvRequest invZoneDto = new SearchInvRequest();
		        invZoneDto.setLotno(lotnoStr);
		        invZoneDto.setSkuId(gdnDtl.getSkuId());
		        invZoneDto.setVendorId(gdnDtl.getVendor());
		        invZoneDto.setInvAttr(gdnDtl.getInvAttr());
		        invZoneDto.setQaStatus(gdnDtl.getQaStatus());
		        invZoneDto.setFactory(gdnHeader.getFactory());
		        
		        // 发货单未拣货数量
		        List<Integer> gdnWhsIdList = items.stream().map(ConfirmInvZoneItemRequest::getWhsId).distinct().collect(Collectors.toList());
	        	List<GdnUnPickGroupWhsDto> unPickGroupWhsList = gdnDtlMapper.selectUnPickGroupWhs(gdnDtl.getSkuId(), lotnoStr, gdnWhsIdList);
		        Map<Integer, GdnUnPickGroupWhsDto> unPickGroupWhsMap = unPickGroupWhsList.stream().collect(Collectors.toMap(GdnUnPickGroupWhsDto::getWhsId, gdnUnPickGroupWhsDto -> gdnUnPickGroupWhsDto));
				for (ConfirmInvZoneItemRequest item : items) {
					// 没有这个仓库的权限
					if(!whsIdList.contains(item.getWhsId())) {
						Shift.fatal("不允许分库，没有" + item.getWhsName() + "仓库的权限");
					}
					whsPreAlocQty = item.getQty().intValue();
					if (item.getManualDeal() == null || !item.getManualDeal()) {
						// 传入各自仓库ID
						invZoneDto.setWhsId(item.getWhsId());
						
						// 校验仓库的可用库存是否足够
						whsAvailableQty = 0;
						List<AvailableInvZoneByWhsResponse> availableInvZone = invZoneMapper.getAvailableInvZoneByWhs(invZoneDto);
						for (AvailableInvZoneByWhsResponse invZone : availableInvZone) {
							whsAvailableQty += invZone.getAvailableQty().intValue();
						}
						// 扣去未拣货的数量
						GdnUnPickGroupWhsDto unPickDto = unPickGroupWhsMap.get(item.getWhsId());
						if(unPickDto != null) {
							int unPickQty = (unPickDto.getOrderQty().subtract(unPickDto.getPickQty())).intValue();
							whsAvailableQty = whsAvailableQty - unPickQty;
						}
						// 仓库预配数量 > 仓库的可用数量
						if (whsPreAlocQty > whsAvailableQty) {
							Shift.fatal(StatusCode.NE_AVAILABLEINVZONE);
						}
						// 拆分
						GdnDtl gdnDtlWhs = new GdnDtl();
				        BeanUtil.copyNonNull(gdnDtl, gdnDtlWhs);
				        if(ctnrLoading != null) {
				        	gdnDtlWhs.setArrangeCtnrFlag(GdnDtlArrangeCtnrFlagEnum.YES.code);
				        } else {
				        	gdnDtlWhs.setArrangeCtnrFlag(GdnDtlArrangeCtnrFlagEnum.NO.code);
				        }
				        gdnDtlWhs.setWhsId(item.getWhsId());
				        gdnDtlWhs.setUdf1(GdnDtlUdf1Enum.YES.code);
				        gdnDtlWhs.setOrderQty(new BigDecimal(whsPreAlocQty));
				        gdnDtlWhs.setPreAlocQty(new BigDecimal(whsPreAlocQty));
						if (++i == 1) {	// 更新原单
				        	gdnDtlWhs.setModifyUser(loginName);
					        gdnDtlWhs.setModifyTime(date);
					        gdnDtlMapper.updateById(gdnDtlWhs);
				        } else {		// 拆分新单
				        	gdnDtlWhs.setGdnDtlId(null);
				        	gdnDtlWhs.setModifyUser(null);
					        gdnDtlWhs.setModifyTime(null);
				        	gdnDtlWhs.setCreateTime(date);
				        	gdnDtlWhs.setCreateUser(loginName);
				        	gdnDtlWhs.setGdnLineNo(++lockMaxGdnLineNo);
					        gdnDtlMapper.insert(gdnDtlWhs);
				        }


						// 新增排柜单信息
						if(ctnrLoading != null) {
							ctnrLoading.setCtnrLoadingId(null);
							ctnrLoading.setPlanQty(gdnDtlWhs.getOrderQty());
							ctnrLoading.setGdnDtlId(gdnDtlWhs.getGdnDtlId());
							ctnrLoading.setGdnLineNo(gdnDtlWhs.getGdnLineNo());
							ctnrLoadingMapper.insert(ctnrLoading);
						}
						// 分到每个库区
						for (AvailableInvZoneByWhsResponse invZone : availableInvZone) {
							// 剩余的仓库预配数量等于0时结束库区分配，进入下一下仓库分配，或者分库结束
							if (whsPreAlocQty == 0) {
								break;
							}
							
							zoneAvailableQty = invZone.getAvailableQty().intValue();
							if (whsPreAlocQty < zoneAvailableQty) {
								// 剩余的仓库预配数量 < 库区的可用数量，【库区预配数量 = 剩余的仓库预配数量】
								zonePreAlocQty = whsPreAlocQty;
							} else {
								// 剩余的仓库预配数量 >= 库区的可用数量，【库区预配数量 = 库区的可用数量】
								zonePreAlocQty = zoneAvailableQty;
							}
							// 剩余的仓库预配数量
							whsPreAlocQty = (whsPreAlocQty - zonePreAlocQty);
							
							confirmInvZone(lotnoStr, gdnDtlWhs, gdnHeader, invZone.getInvZoneId(), 
									new BigDecimal(zonePreAlocQty), loginName, date);
						}
					} else {
						// 手动分的没有可用库存的仓库
						// 拆分新单（带着仓库）
						GdnDtl gdnDtlWhs = new GdnDtl();
				        BeanUtil.copyNonNull(gdnDtl, gdnDtlWhs);
				        
				        gdnDtlWhs.setWhsId(item.getWhsId());
				        gdnDtlWhs.setUdf1(GdnDtlUdf1Enum.NO.code);
				        gdnDtlWhs.setOrderQty(new BigDecimal(whsPreAlocQty));
						if (++i == 1) {	// 更新原单
				        	gdnDtlWhs.setModifyUser(loginName);
					        gdnDtlWhs.setModifyTime(date);
					        gdnDtlMapper.updateById(gdnDtlWhs);
				        } else {		// 拆分新单
				        	gdnDtlWhs.setGdnDtlId(null);
				        	gdnDtlWhs.setModifyUser(null);
					        gdnDtlWhs.setModifyTime(null);
				        	gdnDtlWhs.setCreateTime(date);
				        	gdnDtlWhs.setCreateUser(loginName);
				        	gdnDtlWhs.setGdnLineNo(++lockMaxGdnLineNo);
					        gdnDtlMapper.insert(gdnDtlWhs);
				        }
					}
				}
				
				// 还有没有分配的数量
				if(remainQty > 0) {
					// 拆分新单（不带仓库）
					GdnDtl gdnDtlWhs = new GdnDtl();
			        BeanUtil.copyNonNull(gdnDtl, gdnDtlWhs);
			        
			        gdnDtlWhs.setGdnDtlId(null);
			        gdnDtlWhs.setWhsId(null);
		        	gdnDtlWhs.setModifyUser(null);
			        gdnDtlWhs.setModifyTime(null);
			        gdnDtlWhs.setUdf1(GdnDtlUdf1Enum.NO.code);
			        gdnDtlWhs.setGdnLineNo(++lockMaxGdnLineNo);
			        gdnDtlWhs.setOrderQty(new BigDecimal(remainQty));
			        gdnDtlWhs.setCreateUser(loginName);
			        gdnDtlWhs.setCreateTime(date);
			        gdnDtlMapper.insert(gdnDtlWhs);
				}
			} catch (Exception e) {
				e.printStackTrace();
				throw e;
			} finally {
				log.info("发货单明细锁释放：" + lockKeyStr);
				redisService.unlock(lockKeyStr);
			}
		} else {
			Shift.fatal("当前发货单已在分库调度任务处理中");
		}
		//记录首次分库时间
		GdnHeader splitHeader = gdnHeaderMapper.selectOne(new QueryWrapper<GdnHeader>().eq("GDN_HEADER_ID", gdnDtl.getGdnHeaderId()));
		if (splitHeader.getSplitDate()==null){
			gdnHeaderMapper.updateGdnSpliDate(splitHeader.getGdnNo());
		}
		return new Result<>();
	}
	/*@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
	public synchronized Result<?> confirmInvZone(ConfirmInvZoneRequest dto,
			HttpServletRequest servletRequest) throws Exception {
		// 发货单明细
		GdnDtl gdnDtl = gdnDtlMapper.selectById(dto.getDtlId());
		if (gdnDtl.getWhsId() != null) {
			Shift.fatal(StatusCode.NOTCAN_PREALOC);
		}
		
		String lockKeyStr = LockString.WMS_GDN_DTL_LOCK_KEY + gdnDtl.getGdnDtlId();
		if (redisService.lock(lockKeyStr, LockNumber.THIRTY_SECONDS)) {
			try {
				// 分配库存集合
				List<ConfirmInvZoneItemRequest> items = dto.getItems();
				int qty = 0;
				int orderQty = gdnDtl.getOrderQty().intValue();
				for (ConfirmInvZoneItemRequest item : items) {
					qty += item.getQty().intValue();
				}
				if(orderQty < qty) {
					Shift.fatal(StatusCode.GT_ORDER_QTY);	// 需求数量 < 分配数
				} else if (orderQty > qty) {
					Shift.fatal(StatusCode.NE_ORDER_QTY);	// 需求数量 > 分配数
				}
				
				// 查询当前用户权限仓库
				List<Integer> whsIdList = warehouseService.getWareHouseIds(servletRequest);
				
				// 找批次号
				Lotno lotno = lotnoService.getLotnoByGdnDtlId(gdnDtl.getGdnDtlId());
				if (lotno == null) {
					Shift.fatal(StatusCode.LOTNO_NULL);
				}
				
				// 发货单表头
				GdnHeader gdnHeader = gdnHeaderMapper.selectById(gdnDtl.getGdnHeaderId());
				String loginName = HttpSessionUtil.getLoginName(servletRequest);
				Date date = new Date();
				
				// 排柜单信息
				CtnrLoading ctnrLoading = null;
				if(gdnHeader.getCntrNo() != null || gdnHeader.getSealNo() != null || 
						gdnHeader.getBookingNo() != null || gdnHeader.getVehicleNo() != null) {
					ctnrLoading = new CtnrLoading();
					ctnrLoading.setGdnNo(gdnHeader.getGdnNo());
			    	ctnrLoading.setCntrNo(gdnHeader.getCntrNo());
			    	ctnrLoading.setSealNo(gdnHeader.getSealNo());
			    	ctnrLoading.setCntrType(gdnHeader.getCntrType());
			    	ctnrLoading.setBookingNo(gdnHeader.getBookingNo());
			    	ctnrLoading.setVehicleNo(gdnHeader.getVehicleNo());
			    	
			    	ctnrLoading.setCreateTime(date);
			    	ctnrLoading.setCreateUser(loginName);
			    	ctnrLoading.setCmpQty(BigDecimal.ZERO);
			    	ctnrLoading.setStatus(CtnrLoadingStatusEnum.CREATE.code);
			    	
			    	ctnrLoading.setCntrSeq(gdnHeader.getCntrSeq());
			    	ctnrLoading.setCarrier(gdnHeader.getCarrierId());
			    	ctnrLoading.setRefCntrNo(gdnHeader.getRefCntrNo());
			    	ctnrLoading.setRefCntrType(gdnHeader.getCntrType());
			    	ctnrLoading.setDockOfLoading(gdnHeader.getShipPort());			// 装柜码头
			    	ctnrLoading.setPlanLoadingTime(gdnHeader.getPlanLoadingTime());
				}
				
				// 锁住最大行号
		        Integer lockMaxGdnLineNo = 0;
		        if(items.size() > 0) {
		        	lockMaxGdnLineNo = gdnDtlMapper.lockMaxGdnLineNo(gdnHeader.getGdnHeaderId());
		        }
		        
		        // 仓库预配数量
		        int whsPreAlocQty;
		        // 库区预配数量
				int zonePreAlocQty;
				// 仓库的可用数量
				int whsAvailableQty;
				// 库区的可用数量
				int zoneAvailableQty;
		        
		        // 遍历每个仓库分配多少数量
		        int i = 0;
		        
				// 查找库区库存入参DTO
				SearchInvRequest invZoneDto = new SearchInvRequest();
		        invZoneDto.setLotno(lotno.getLotno());
		        invZoneDto.setSkuId(gdnDtl.getSkuId());
		        invZoneDto.setVendorId(gdnDtl.getVendor());
		        invZoneDto.setInvAttr(gdnDtl.getInvAttr());
		        invZoneDto.setQaStatus(gdnDtl.getQaStatus());
		        invZoneDto.setFactory(gdnHeader.getFactory());
				for (ConfirmInvZoneItemRequest item : items) {
					// 没有这个仓库的权限
					if(!whsIdList.contains(item.getWhsId())) {
						Shift.fatal("不允许分库，没有" + item.getWhsName() + "仓库的权限");
					}
					
					// 传入各自仓库ID
					invZoneDto.setWhsId(item.getWhsId());
								
					// 校验仓库的可用库存是否足够
					whsAvailableQty = 0;
					List<AvailableInvZoneByWhsResponse> availableInvZone = invZoneMapper.getAvailableInvZoneByWhs(invZoneDto);
					for (AvailableInvZoneByWhsResponse invZone : availableInvZone) {
						whsAvailableQty += invZone.getAvailableQty().intValue();
					}
					// 仓库预配数量 > 仓库的可用数量
					whsPreAlocQty = item.getQty().intValue();
			        if (whsPreAlocQty > whsAvailableQty) {
						Shift.fatal(StatusCode.NE_AVAILABLEINVZONE);
					}
			        
			        // 拆分
			        GdnDtl gdnDtlWhs = new GdnDtl();
			        BeanUtil.copyNonNull(gdnDtl, gdnDtlWhs);
			        gdnDtlWhs.setWhsId(item.getWhsId());
			        gdnDtlWhs.setOrderQty(new BigDecimal(whsPreAlocQty));
			        gdnDtlWhs.setPreAlocQty(new BigDecimal(whsPreAlocQty));
					if (++i == 1) {	// 更新原单
			        	gdnDtlWhs.setModifyUser(loginName);
				        gdnDtlWhs.setModifyTime(date);
				        gdnDtlMapper.updateById(gdnDtlWhs);
			        } else {		// 拆分新单
			        	gdnDtlWhs.setGdnDtlId(null);
			        	gdnDtlWhs.setCreateTime(date);
			        	gdnDtlWhs.setCreateUser(loginName);
			        	gdnDtlWhs.setGdnLineNo(++lockMaxGdnLineNo);
				        gdnDtlMapper.insert(gdnDtlWhs);
			        }
					
					// 新增排柜单信息
					if(ctnrLoading != null) {
						ctnrLoading.setCtnrLoadingId(null);
						ctnrLoading.setPlanQty(gdnDtlWhs.getOrderQty());
						ctnrLoading.setGdnDtlId(gdnDtlWhs.getGdnDtlId());
						ctnrLoading.setGdnLineNo(gdnDtlWhs.getGdnLineNo());
						ctnrLoadingMapper.insert(ctnrLoading);
					}
			        
			        // 分到每个库区
					for (AvailableInvZoneByWhsResponse invZone : availableInvZone) {
						// 剩余的仓库预配数量等于0时结束库区分配，进入下一下仓库分配，或者分库结束
						if (whsPreAlocQty == 0) {
							break;
						}
						
						zoneAvailableQty = invZone.getAvailableQty().intValue();
						if (whsPreAlocQty < zoneAvailableQty) {
							// 剩余的仓库预配数量 < 库区的可用数量，【库区预配数量 = 剩余的仓库预配数量】
							zonePreAlocQty = whsPreAlocQty;
						} else {
							// 剩余的仓库预配数量 >= 库区的可用数量，【库区预配数量 = 库区的可用数量】
							zonePreAlocQty = zoneAvailableQty;
						}
						// 剩余的仓库预配数量
						whsPreAlocQty = (whsPreAlocQty - zonePreAlocQty);
						
						confirmInvZone(lotno.getLotno(), gdnDtlWhs, gdnHeader, invZone.getInvZoneId(), 
								new BigDecimal(zonePreAlocQty), loginName, date);
					}
				}
			} catch (Exception e) {
				e.printStackTrace();
				throw e;
			} finally {
				log.info("发货单明细锁释放：" + lockKeyStr);
				redisService.unlock(lockKeyStr);
			}
		} else {
			Shift.fatal("当前发货单已在分库调度任务处理中");
		}
		return new Result<>();
	}*/
	
	/**
	 * 取消分配库存
	 * @param servletRequest
	 * @return
	 * 
	 * a.校验：(UDF1 = YES & 拣货任务标识 = 0（未生成）) || (UDF1 = NO & WHS_ID != NULL )
	 * b.调用【取消发货单库存预配】服务，将发货单库存预配数据状态变更为“0”(无效)，
	 * 同时更新库区库存表(WMS_INV_ZONE，减少库区预配库存)。
	 */
	@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
	public synchronized Result<?> cancelInvZone(Integer gdnDtlId, HttpServletRequest servletRequest) {
		// 发货单明细
		GdnDtl gdnDtl = gdnDtlMapper.selectById(gdnDtlId);
		if (!((GdnDtlUdf1Enum.YES.code.equals(gdnDtl.getUdf1()) && gdnDtl.getPickTaskFlag() == GdnDtlPickTaskFlagEnum.NO.code) 
				|| (GdnDtlUdf1Enum.NO.code.equals(gdnDtl.getUdf1()) && gdnDtl.getWhsId() != null))) {
			Shift.fatal(StatusCode.NOTCAN_CANCEL);
		}

		String loginName = HttpSessionUtil.getLoginName(servletRequest);

		// 置空发货单明细的 【仓库】和【预配数量】
		gdnDtlMapper.emptyWhsAndPreAlocQty(GdnDtlUdf1Enum.NO.code, loginName, gdnDtlId);
		if(GdnDtlUdf1Enum.YES.code.equals(gdnDtl.getUdf1())) {
			// 发货单表头
			GdnHeader gdnHeader = gdnHeaderMapper.selectById(gdnDtl.getGdnHeaderId());
			Date date = new Date();

			// 获取发货单库存预配数据列表
			QueryWrapper<DocPreAloc> gdnPreAlocQueryWrapper = new QueryWrapper<>();
			gdnPreAlocQueryWrapper.eq("DOC_DTL_ID", gdnDtlId);
			gdnPreAlocQueryWrapper.eq("DOC_TYPE", gdnHeader.getGdnType());
			gdnPreAlocQueryWrapper.eq("STATUS", DocPreAlocStatusEnum.EFFECTIVE.code);
			/*for (DocPreAloc gdnPreAloc : docPreAlocMapper.selectList(gdnPreAlocQueryWrapper)) {
				// 更新库区库存预配数量
				UpdateInvZoneQtyDto updateInvZoneQtyDto = new UpdateInvZoneQtyDto();
				updateInvZoneQtyDto.setInvZoneId(Integer.parseInt(gdnPreAloc.getUdf1()));
				updateInvZoneQtyDto.setPreAlocQty(gdnPreAloc.getPreAlocQty().negate());
				updateInvZoneQtyDto.setOperator(loginName);
				inventoryService.updateInvZoneQty(updateInvZoneQtyDto);

				// 生成库区库存快照
				InvZone invZone = invZoneMapper.selectById(updateInvZoneQtyDto.getInvZoneId());
				InvZoneHis invZoneHis = new InvZoneHis();
				BeanUtil.copyNonNull(invZone, invZoneHis);
				invZoneHis.setCreateTime(date);
				invZoneHis.setSnapshootDate(date);
				invZoneHis.setCreateUser(loginName);
				invZoneHis.setPreAlocQty(invZoneHis.getPreAlocQty().subtract(gdnPreAloc.getPreAlocQty()));
				invZoneHisMapper.insert(invZoneHis);
			}*/
			// 将发货单库存预配数据状态变更为“0”(无效)
			DocPreAloc docPreAloc = new DocPreAloc();
			docPreAloc.setModifyTime(date);
			docPreAloc.setModifyUser(loginName);
			docPreAloc.setStatus(DocPreAlocStatusEnum.INVALID.code);
			docPreAlocMapper.update(docPreAloc, gdnPreAlocQueryWrapper);

			// 删除对应的装柜单
			QueryWrapper<CtnrLoading> ctnrLoadingQueryWrapper = new QueryWrapper<CtnrLoading>();
			ctnrLoadingQueryWrapper.eq("GDN_DTL_ID", gdnDtlId);
			ctnrLoadingQueryWrapper.eq("GDN_NO", gdnHeader.getGdnNo());
			ctnrLoadingMapper.delete(ctnrLoadingQueryWrapper);

			//符合条件清除初次分库时间
            Integer splitCount = gdnDtlMapper.selectSplitCoutnt(gdnHeader.getGdnHeaderId(), GdnDtlUdf1Enum.YES.code);
            if (splitCount.equals(0)){
                gdnHeaderMapper.updateGdnSpliNull(gdnHeader.getGdnNo());
            }
        }
		return new Result<>();
	}
	
	/**
	 * 原装柜信息
	 * @param gdnHeaderId
	 * @return
	 */
	public CtnrLoadingPrintResponse searchCtnrLoadingPrint(Integer gdnHeaderId) {
		return gdnHeaderMapper.selectPrintByGdnHeaderId(gdnHeaderId);
    }
	
	/**
	 * 编辑原装柜信息备注
	 * @param dto
	 * @param servletRequest
	 * @return
	 */
	@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
	public Result<?> updateGdnDtlComment(UpdateGdnDtlCommentRequest dto,
			HttpServletRequest servletRequest) {
		String loginName = HttpSessionUtil.getLoginName(servletRequest);
		gdnHeaderMapper.updateCommentsAndErrorCommentsByGdnHeaderId(dto.getComments(), dto.getErrorComments(), loginName, dto.getGdnHeaderId());
		return new Result<>();
    }
	
	/**
	 * 原装柜信息列表
	 * @param gdnHeaderId
	 * @param pager
	 * @return
	 */
	public <T> PagerInfo<List<CtnrLoadingPrintListResponse>> searchCtnrLoadingPrintList(Integer gdnHeaderId, Pager<T> pager) {
    	Page<?> page = PageHelper.offsetPage(pager.getSkipCount(), pager.getMaxResultCount());
        PagerInfo<List<CtnrLoadingPrintListResponse>> pagerInfo = new PagerInfo<List<CtnrLoadingPrintListResponse>>();
        List<CtnrLoadingPrintListResponse> list = gdnDtlMapper.selectPrintListByGdnHeaderId(gdnHeaderId);
        pagerInfo.setItems(list);
        pagerInfo.setTotalCount(page.getTotal());
		return pagerInfo;
    }
	
	/**
	 * 打印余留单pdf
	 * @param gdnHeaderId
	 * @param servletRequest
	 * @param response
	 * @throws Exception
	 * 
	 */
	@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
	public void loadingRemainPrint(Integer gdnHeaderId,
			HttpServletRequest servletRequest, HttpServletResponse response) throws Exception {
		InputStream inputStream = null;
		OutputStream outputStream = null;
		try {
			int printFlag = PrintFlagEnum.YES.getCode();
			String loginName = HttpSessionUtil.getLoginName(servletRequest);
			Date date = new Date();
			
			// 发货单表头
			GdnHeader gdnHeader = gdnHeaderMapper.selectById(gdnHeaderId);
			gdnHeader.setRemainDocPrint(printFlag);
			gdnHeader.setModifyUser(loginName);
			gdnHeader.setModifyTime(date);
			gdnHeaderMapper.updateById(gdnHeader);
			
			// 装柜余留单表头
			QueryWrapper<GdnRemainHeader> queryWrapper = new QueryWrapper<GdnRemainHeader>();
			queryWrapper.eq("GDN_HEADER_ID", gdnHeaderId);
			GdnRemainHeader gdnRemainHeader = gdnRemainHeaderMapper.selectOne(queryWrapper);
			gdnRemainHeader.setPrintFlag(printFlag);
			gdnRemainHeader.setModifyUser(loginName);
			gdnRemainHeader.setModifyTime(date);
			gdnRemainHeaderMapper.updateById(gdnRemainHeader);
			
			// 获取文件流
			ClassPathResource resource = new ClassPathResource(FileUrlString.LOADING_REMAIN_PRINT);
			inputStream = resource.getInputStream();
			JasperReport jasperReport = (JasperReport) JRLoader.loadObject(inputStream);
			
			// 入参
			Map<String, Object> parameters = new HashMap<String, Object>(1);
			parameters.put("GDN_REMAIN_HEADER_ID", gdnRemainHeader.getGdnRemainHeaderId());
			JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, parameters, dataSource.getConnection());
			
			// 设置pdf尺寸
			jasperPrint.setPageWidth(595);
			jasperPrint.setPageHeight(396);
			jasperPrint.setLeftMargin(0);
			jasperPrint.setRightMargin(0);
			jasperPrint.setTopMargin(0);
			jasperPrint.setBottomMargin(0);
			
			String pdfName = new String("装柜余留单".getBytes(), "iso8859-1") + ".xlsx";
			response.setContentType("application/xls");   
			response.setCharacterEncoding("UTF-8"); 
			response.setHeader("Content-Disposition", "attachment; filename=" + pdfName);
			outputStream = response.getOutputStream();
			
			// Xls格式的导出器 JRXlsAbstractExport
			JRXlsxExporter exporter = new JRXlsxExporter();
			
			//设置输入项   
			ExporterInput exporterInput = new SimpleExporterInput(jasperPrint);
			exporter.setExporterInput(exporterInput);
			
			//设置输出项   
			OutputStreamExporterOutput exporterOutput = new SimpleOutputStreamExporterOutput(outputStream);   
			exporter.setExporterOutput(exporterOutput);
			// 导出
			exporter.exportReport();
		} catch (Exception e){
			e.printStackTrace();
			throw e;
		} finally {
			if(outputStream != null) {
				outputStream.close();
			}
			if(inputStream != null) {
				inputStream.close();
			}
		}
	}


	/**
	 * 打印余留单pdf
	 * @param gdnHeaderId
	 * @param servletRequest
	 * @param response
	 * @throws Exception
	 *
	 */
	@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
	public Result loadingRemainPrintNew(Integer gdnHeaderId,
								   HttpServletRequest servletRequest, HttpServletResponse response) throws Exception {
		InputStream inputStream = null;
		OutputStream outputStream = null;
		Connection connection =null;
		try {
			int printFlag = PrintFlagEnum.YES.getCode();
			String loginName = HttpSessionUtil.getLoginName(servletRequest);
			Date date = new Date();

			// 发货单表头
			GdnHeader gdnHeader = gdnHeaderMapper.selectById(gdnHeaderId);
			gdnHeader.setRemainDocPrint(printFlag);
			gdnHeader.setModifyUser(loginName);
			gdnHeader.setModifyTime(date);
			gdnHeaderMapper.updateById(gdnHeader);

			// 装柜余留单表头
			QueryWrapper<GdnRemainHeader> queryWrapper = new QueryWrapper<GdnRemainHeader>();
			queryWrapper.eq("GDN_HEADER_ID", gdnHeaderId);
			GdnRemainHeader gdnRemainHeader = gdnRemainHeaderMapper.selectOne(queryWrapper);
			gdnRemainHeader.setPrintFlag(printFlag);
			gdnRemainHeader.setModifyUser(loginName);
			gdnRemainHeader.setModifyTime(date);
			gdnRemainHeaderMapper.updateById(gdnRemainHeader);

			// 获取文件流
			ClassPathResource resource = new ClassPathResource(FileUrlString.LOADING_REMAIN_PRINT);
			inputStream = resource.getInputStream();
			JasperReport jasperReport = (JasperReport) JRLoader.loadObject(inputStream);

			// 入参
			Map<String, Object> parameters = new HashMap<String, Object>(1);
			parameters.put("GDN_REMAIN_HEADER_ID", gdnRemainHeader.getGdnRemainHeaderId());
			connection = dataSource.getConnection();
			JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, parameters,connection );

			// 设置pdf尺寸
			jasperPrint.setPageWidth(595);
			jasperPrint.setPageHeight(396);
			jasperPrint.setLeftMargin(0);
			jasperPrint.setRightMargin(0);
			jasperPrint.setTopMargin(0);
			jasperPrint.setBottomMargin(0);

			String absolutePath = fileService.saveFile(jasperPrint, "余留单", "xlsx");
			//返回对应的路径
			Result result = new Result();
			result.setData(absolutePath);

			return result;


		} catch (Exception e){
			e.printStackTrace();
			throw e;
		} finally {
			if(outputStream != null) {
				outputStream.close();
			}
			if(inputStream != null) {
				inputStream.close();
			}
			if(connection!=null){
				connection.close();
			}
		}
	}


	/**
	 * 打印发货单pdf
	 * @param gdnHeaderId
	 * @param servletRequest
	 * @param response
	 * @throws Exception
	 */
	@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
	public void loadingPrint(Integer gdnHeaderId,
			HttpServletRequest servletRequest, HttpServletResponse response) throws Exception {
		// 查找发货单表头
		GdnHeader gdnHeader = gdnHeaderMapper.selectById(gdnHeaderId);
		
		OutputStream outputStream = null;
		InputStream inputStream = null;
		try {
			int printFlag = PrintFlagEnum.YES.getCode();
			String loginName = HttpSessionUtil.getLoginName(servletRequest);
			Date date = new Date();
			
			// 更新发货单表头
			gdnHeader.setGdnPrint(printFlag);
			gdnHeader.setModifyUser(loginName);
			gdnHeader.setModifyTime(date);
			gdnHeaderMapper.updateById(gdnHeader);
			
			// 获取模板文件流
			ClassPathResource resource = new ClassPathResource(FileUrlString.LOADING_PRINT);
			inputStream = resource.getInputStream();
			JasperReport jasperReport = (JasperReport) JRLoader.loadObject(inputStream);
			
			// 入参
			Map<String, Object> parameters = new HashMap<String, Object>(2);
			parameters.put("USER_NAME", loginName);
			parameters.put("GDN_HEADER_ID", gdnHeaderId);
			JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, parameters, dataSource.getConnection());
			
			// 设置pdf尺寸
			jasperPrint.setPageWidth(595);
			jasperPrint.setPageHeight(396);
			jasperPrint.setLeftMargin(0);
			jasperPrint.setRightMargin(0);
			jasperPrint.setTopMargin(0);
			jasperPrint.setBottomMargin(0);
			log.info("保存文件开始");
			//将文件保存到本地服务器
           /* String fileName  = File.separator+"tmp"+ File.separator+"test.xlxs";
            JRXlsxExporter exporter = new JRXlsxExporter();
            //设置输入项
			ExporterInput exporterInput = new SimpleExporterInput(jasperPrint);
			exporter.setExporterInput(exporterInput);
			OutputStreamExporterOutput exporterOutput = new SimpleOutputStreamExporterOutput(fileName);
			exporter.setExporterOutput(exporterOutput);
			exporter.exportReport();*/
			//将文件保存到本地服务器结束
            //log.info("保存文件结束");

			String pdfName = new String("发货单".getBytes(), "iso8859-1") + ".xlsx";
			response.setContentType("application/xls");
			response.setCharacterEncoding("UTF-8"); 
			response.setHeader("Content-Disposition", "attachment; filename=" + pdfName);
			outputStream = response.getOutputStream();
			
			// Xls格式的导出器 JRXlsAbstractExport
			JRXlsxExporter exporter = new JRXlsxExporter();
			
			//设置输入项   
			ExporterInput exporterInput = new SimpleExporterInput(jasperPrint);
			exporter.setExporterInput(exporterInput);
			
			//设置输出项   
			OutputStreamExporterOutput exporterOutput = new SimpleOutputStreamExporterOutput(outputStream);   
			exporter.setExporterOutput(exporterOutput);
			// 导出
			exporter.exportReport();

		} catch (Exception e){
			e.printStackTrace();
			throw e;
		} finally {
			if(outputStream != null) {
				outputStream.close();
			}
			if(inputStream != null) {
				inputStream.close();
			}
		}
	}


	/**
	 * 打印发货单pdf
	 * @param gdnHeaderId
	 * @param servletRequest
	 * @param response
	 * @throws Exception
	 */
	@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
	public Result loadingPrintNew(Integer gdnHeaderId,
							 HttpServletRequest servletRequest, HttpServletResponse response) throws Exception {
		// 查找发货单表头
		GdnHeader gdnHeader = gdnHeaderMapper.selectById(gdnHeaderId);

		OutputStream outputStream = null;
		InputStream inputStream = null;
		Connection connection =null ;
		try {
			int printFlag = PrintFlagEnum.YES.getCode();
			String loginName = HttpSessionUtil.getLoginName(servletRequest);
			Date date = new Date();

			// 更新发货单表头
			gdnHeader.setGdnPrint(printFlag);
			gdnHeader.setModifyUser(loginName);
			gdnHeader.setModifyTime(date);
			gdnHeaderMapper.updateById(gdnHeader);

			// 获取模板文件流
			ClassPathResource resource = new ClassPathResource(FileUrlString.LOADING_PRINT);
			inputStream = resource.getInputStream();
			JasperReport jasperReport = (JasperReport) JRLoader.loadObject(inputStream);

			// 入参
			Map<String, Object> parameters = new HashMap<String, Object>(2);
			parameters.put("USER_NAME", loginName);
			parameters.put("GDN_HEADER_ID", gdnHeaderId);
			connection =dataSource.getConnection();
			JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, parameters, connection);

			// 设置pdf尺寸
			jasperPrint.setPageWidth(595);
			jasperPrint.setPageHeight(396);
			jasperPrint.setLeftMargin(0);
			jasperPrint.setRightMargin(0);
			jasperPrint.setTopMargin(0);
			jasperPrint.setBottomMargin(0);
			log.info("保存文件开始");
			//将文件保存到本地服务器
			String absolutePath = fileService.saveFile(jasperPrint, "发货单", "xlsx");
			//返回对应的路径
            Result result = new Result();
            result.setData(absolutePath);

        	return result;
		} catch (Exception e){
			e.printStackTrace();
			throw e;
		} finally {
			if(outputStream != null) {
				outputStream.close();
			}
			if(inputStream != null) {
				inputStream.close();
			}
			if(connection!=null){
				connection.close();
			}
		}
	}



	/**
	 * 打印发货单pdf
	 * @param gdnHeaderId
	 * @param servletRequest
	 * @param response
	 * @throws Exception
	 */
	/*@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
	public void loadingPrint(Integer gdnHeaderId,
			HttpServletRequest servletRequest, HttpServletResponse response) throws Exception {
		// 查找发货单表头
		GdnHeader gdnHeader = gdnHeaderMapper.selectById(gdnHeaderId);
		
		OutputStream outputStream = null;
		InputStream inputStream = null;
		try {
			int printFlag = PrintFlagEnum.YES.getCode();
			String loginName = HttpSessionUtil.getLoginName(servletRequest);
			Date date = new Date();
			
			// 更新发货单表头
			gdnHeader.setGdnPrint(printFlag);
			gdnHeader.setModifyUser(loginName);
			gdnHeader.setModifyTime(date);
			gdnHeaderMapper.updateById(gdnHeader);
			
			// 获取模板文件流
			String pdfName = new String("发货单".getBytes(), "iso8859-1") + ".pdf";
			ClassPathResource resource = new ClassPathResource(FileUrlString.LOADING_PRINT);
			inputStream = resource.getInputStream();
			JasperReport jasperReport = (JasperReport) JRLoader.loadObject(inputStream);
			
			// 优化性能
			DefaultJasperReportsContext context = DefaultJasperReportsContext.getInstance();
			JRPropertiesUtil.getInstance(context).setProperty("net.sf.jasperreports.xpath.executer.factory", 
					"net.sf.jasperreports.engine.util.xml.JaxenXPathExecuterFactory");
			
			// 入参
			Map<String, Object> parameters = new HashMap<String, Object>(2);
			parameters.put("USER_NAME", loginName);
			parameters.put("GDN_HEADER_ID", gdnHeaderId);
			JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, parameters, dataSource.getConnection());
			
			// 设置pdf尺寸
			jasperPrint.setPageWidth(595);
			jasperPrint.setPageHeight(396);
			jasperPrint.setLeftMargin(0);
			jasperPrint.setRightMargin(0);
			jasperPrint.setTopMargin(0);
			jasperPrint.setBottomMargin(0);
			
			response.setContentType("application/pdf");
			response.setHeader("Content-Disposition", "attachment; filename=" + pdfName);
			outputStream = response.getOutputStream();
			JasperExportManager.exportReportToPdfStream(jasperPrint, outputStream);
		} catch (Exception e){
			e.printStackTrace();
			throw e;
		} finally {
			if(outputStream != null) {
				outputStream.close();
			}
			if(inputStream != null) {
				inputStream.close();
			}
		}
	}
	
	/*@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
	public void loadingPrint(String gdnNo,
			HttpServletRequest servletRequest, HttpServletResponse response) throws Exception {
		// 查找发货单表头
		QueryWrapper<GdnHeader> queryWrapper = new QueryWrapper<GdnHeader>();
		queryWrapper.eq("GDN_NO", gdnNo);
		GdnHeader gdnHeader = gdnHeaderMapper.selectOne(queryWrapper);
		
		// 查找仓库为空的数量
		QueryWrapper<GdnDtl> gdnDtlQueryWrapper = new QueryWrapper<GdnDtl>();
		gdnDtlQueryWrapper.eq("GDN_HEADER_ID", gdnHeader.getGdnHeaderId());
		gdnDtlQueryWrapper.isNull("WHS_ID");
		Integer gdnDtlCount = gdnDtlMapper.selectCount(gdnDtlQueryWrapper);
		
		// 所有明细仓库不为空
		if(gdnDtlCount > 0) {
			Shift.fatal(StatusCode.NOTCAN_LOADINGPRINTINVOICE);
		}
		
		OutputStream outputStream = null;
		InputStream inputStream = null;
		try {
			String loginName = HttpSessionUtil.getLoginName(servletRequest);
			
			// 更新发货单表头
			gdnHeader.setGdnPrint(PrintFlagEnum.YES.getCode());
			gdnHeader.setModifyUser(loginName);
			gdnHeader.setModifyTime(new Date());
			gdnHeaderMapper.updateById(gdnHeader);
			
			// 获取模板文件流
			ClassPathResource resource = new ClassPathResource(FileUrlString.LOADING_PRINT);
			inputStream = resource.getInputStream();
			JasperReport jasperReport = (JasperReport) JRLoader.loadObject(inputStream);
			
			// 优化性能
			DefaultJasperReportsContext context = DefaultJasperReportsContext.getInstance();
			JRPropertiesUtil.getInstance(context).setProperty("net.sf.jasperreports.xpath.executer.factory", 
					"net.sf.jasperreports.engine.util.xml.JaxenXPathExecuterFactory");
			
			// 模板参数集合
			List<Map<String, Object>> mapGroupList = gdnHeaderMapper.selectPrintAllGroupBy(gdnNo);
			List<JasperPrint> jasperPrintList = new ArrayList<JasperPrint>(mapGroupList.size());
			for (Map<String, Object> mapGroup : mapGroupList) {
				JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, mapGroup, dataSource.getConnection());
				// 设置pdf尺寸
				jasperPrint.setPageWidth(595);
				jasperPrint.setPageHeight(396);
				jasperPrint.setLeftMargin(0);
				jasperPrint.setRightMargin(0);
				jasperPrint.setTopMargin(0);
				jasperPrint.setBottomMargin(0);
				jasperPrintList.add(jasperPrint);
			}
			String pdfName = new String("装柜发货单".getBytes(), "iso8859-1") + ".pdf";
			response.setContentType("application/pdf");
			response.setHeader("Content-Disposition", "attachment; filename=" + pdfName);
			outputStream = response.getOutputStream();
			JRPdfExporter exporter = new JRPdfExporter();
			exporter.setParameter(JRPdfExporterParameter.JASPER_PRINT_LIST, jasperPrintList);
			exporter.setParameter(JRPdfExporterParameter.OUTPUT_STREAM, outputStream);
			exporter.setParameter(JRExporterParameter.CHARACTER_ENCODING, "UTF-8");
			exporter.exportReport();
		} catch (Exception e) {
			e.printStackTrace();
			throw e;
		} finally {
			if(outputStream != null) {
				outputStream.close();
			}
			if(inputStream != null) {
				inputStream.close();
			}
		}
	}*/
	
	// 私有服务
	/**
	 * 【发货单库存预配】服务
	 * 1>将数据保存到发货单预配表(WMS_GDN_PRE_ALOC)、
	 * 2>更新库区库存表(WMS_INV_ZONE，增加库区预配库存)
	 * 3>生成拣货任务(WMS_PICK_TASK)
	 *
	 * @param lotno			批次号
	 * @param invZoneId		库区库存ID
	 * @param preAlocQty	预配数量
	 * @param loginName		
	 * @param date
	 */
	@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
	public void confirmInvZone(String lotno, GdnDtl gdnDtl, GdnHeader gdnHeader,
			Integer invZoneId, BigDecimal preAlocQty, String loginName, Date date) {
		InvZone invZone = invZoneMapper.selectById(invZoneId);
		
		// 更新库区库存预配数量
		/*UpdateInvZoneQtyDto updateInvZoneQtyDto = new UpdateInvZoneQtyDto();
		updateInvZoneQtyDto.setOperator(loginName);
		updateInvZoneQtyDto.setInvZoneId(invZoneId);
		updateInvZoneQtyDto.setPreAlocQty(preAlocQty);
		inventoryService.updateInvZoneQty(updateInvZoneQtyDto);*/
		
		// 生成库区库存快照
		/*InvZoneHis invZoneHis = new InvZoneHis();
		BeanUtil.copyNonNull(invZone, invZoneHis);
		invZoneHis.setCreateTime(date);
		invZoneHis.setSnapshootDate(date);
		invZoneHis.setCreateUser(loginName);
		invZoneHis.setPreAlocQty(invZoneHis.getPreAlocQty().add(preAlocQty));
		invZoneHisMapper.insert(invZoneHis);*/
		
		// 生成发货单预配表
		DocPreAloc docPreAloc = new DocPreAloc();
		docPreAloc.setOwner(gdnHeader.getOwner());
		docPreAloc.setFactory(gdnHeader.getFactory());
		docPreAloc.setUnit(gdnDtl.getUnit());
		docPreAloc.setSkuId(gdnDtl.getSkuId());
		docPreAloc.setVendorId(gdnDtl.getVendor());
		docPreAloc.setInvAttr(gdnDtl.getInvAttr());
		docPreAloc.setQaStatus(gdnDtl.getQaStatus());
		docPreAloc.setDocDtlId(gdnDtl.getGdnDtlId());
		docPreAloc.setWhsId(gdnDtl.getWhsId());
		docPreAloc.setZoneId(invZone.getZoneId());
		docPreAloc.setUdf1(invZone.getInvZoneId().toString());	// UDF1记录库区库存ID
		docPreAloc.setLotno(lotno);
		docPreAloc.setCreateTime(date);
		docPreAloc.setCreateUser(loginName);
		docPreAloc.setPreAlocQty(preAlocQty);
		docPreAloc.setStatus(DocPreAlocStatusEnum.EFFECTIVE.code);
		docPreAloc.setDocType(gdnHeader.getGdnType());
		docPreAlocMapper.insert(docPreAloc);
	}

	//更新装柜顺序
	@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
	public Result<?> updateCtnrSequence(BigDecimal gdnHeaderId,BigDecimal gdnDtlId,Integer ctnrSequence){
		if (ctnrSequence==null){
			Shift.fatal("请选择装柜顺序!");
		}
		//查询装柜顺序集合
		List<Integer> sequenceList = gdnDtlMapper.selectCtnrSequence(gdnHeaderId, gdnDtlId);
		if (!CollectionUtil.isEmpty(sequenceList)){
			if (sequenceList.contains(ctnrSequence)){
				Shift.fatal("装柜顺序不能重复!");
			}
		}
		gdnDtlMapper.updateCtnrSequence(ctnrSequence,gdnDtlId);
		return new Result<>("更新装柜顺序成功!");
	}


}